package org.sophon.commons.util;

import java.util.Collection;
import java.util.Map;

import org.sophon.commons.exception.SophonException;
import org.sophon.commons.exception.ErrorCode;

/**
 * 断言工具类
 * @author moushaokun
 * @since time: 2023-02-16 21:55
 */
public final class AssertUtil {

    public static void assertTrue(boolean expression, ErrorCode errorCode) {
        if (!expression) {
            throw new SophonException(errorCode);
        }
    }

    public static void assertTrue(boolean expression, ErrorCode errorCode, String errorMsg) {
        if (!expression) {
            throw new SophonException(errorCode, errorMsg);
        }
    }

    public static void assertFalse(boolean expression, ErrorCode errorCode) {
        assertTrue(!expression, errorCode);
    }

    public static void assertFalse(boolean expression, ErrorCode errorCode, String errorMsg) {
        assertTrue(!expression, errorCode, errorMsg);
    }

    public static void assertNull(Object object, ErrorCode errorCode) {
        assertTrue(object == null, errorCode);
    }

    public static void assertNull(Object object, ErrorCode errorCode, String errorMsg) {
        assertTrue(object == null, errorCode, errorMsg);
    }

    public static void assertNotNull(Object object, ErrorCode errorCode) {
        assertTrue(object != null, errorCode);
    }

    public static void assertNotNull(Object object, ErrorCode errorCode, String errorMsg) {
        assertTrue(object != null, errorCode, errorMsg);
    }

    public static void assertNotBlank(String text, ErrorCode errorCode) {
        assertTrue(isNotBlank(text), errorCode);
    }

    public static void assertNotBlank(String text, ErrorCode errorCode, String errorMsg) {
        assertTrue(isNotBlank(text), errorCode, errorMsg);
    }

    public static void assertBlank(String text, ErrorCode errorCode) {
        assertTrue(isBlank(text), errorCode);
    }

    public static void assertBlank(String text, ErrorCode errorCode, String errorMsg) {
        assertTrue(isBlank(text), errorCode, errorMsg);
    }

    public static void assertNotEmpty(Collection<?> collection, ErrorCode errorCode) {
        assertTrue(isNotEmpty(collection), errorCode);
    }

    public static void assertNotEmpty(Collection<?> collection, ErrorCode errorCode, String errorMsg) {
        assertTrue(isNotEmpty(collection), errorCode, errorMsg);
    }

    public static void assertEmpty(Collection<?> collection, ErrorCode errorCode) {
        assertTrue(isEmpty(collection), errorCode);
    }

    public static void assertEmpty(Collection<?> collection, ErrorCode errorCode, String errorMsg) {
        assertTrue(isEmpty(collection), errorCode, errorMsg);
    }

    public static void assertNoneNullElements(Object[] array, ErrorCode errorCode) {
        assertNotNull(array, errorCode);
        if (array != null) {
            for (Object element : array) {
                assertNotNull(element, errorCode);
            }
        }
    }

    public static void assertNoneNullElements(Object[] array, ErrorCode errorCode, String errorMsg) {
        assertNotNull(array, errorCode, errorMsg);
        if (array != null) {
            for (Object element : array) {
                assertNotNull(element, errorCode, errorMsg);
            }
        }
    }

    public static void assertNotEmpty(Map<?, ?> map, ErrorCode errorCode) {
        assertTrue(isNotEmpty(map), errorCode);
    }

    public static void assertNotEmpty(Map<?, ?> map, ErrorCode errorCode, String errorMsg) {
        assertTrue(isNotEmpty(map), errorCode, errorMsg);
    }

    public static void assertEmpty(Map<?, ?> map, ErrorCode errorCode) {
        assertTrue(isEmpty(map), errorCode);
    }

    public static void assertEmpty(Map<?, ?> map, ErrorCode errorCode, String errorMsg) {
        assertTrue(isEmpty(map), errorCode, errorMsg);
    }

    public static void assertInstanceOf(Class<?> type, Object obj, ErrorCode errorCode) {
        assertNotNull(type, errorCode);
        assertNotNull(obj, errorCode);
        assertTrue(type.isInstance(obj), errorCode);
    }

    public static void assertInstanceOf(Class<?> type, Object obj, ErrorCode errorCode, String errorMsg) {
        assertNotNull(type, errorCode, errorMsg);
        assertNotNull(obj, errorCode, errorMsg);
        assertTrue(type.isInstance(obj), errorCode, errorMsg);
    }


    //==========工具判断方法=========

    /**
     * <p>Checks if a CharSequence is not empty (""), not null and not whitespace only.</p>
     *
     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
     *
     * <pre>
     * isNotBlank(null)      = false
     * isNotBlank("")        = false
     * isNotBlank(" ")       = false
     * isNotBlank("bob")     = true
     * isNotBlank("  bob  ") = true
     * </pre>
     *
     * @param cs  the CharSequence to check, may be null
     * @return {@code true} if the CharSequence is
     *  not empty and not null and not whitespace only
     */
    public static boolean isNotBlank(final CharSequence cs) {
        return !isBlank(cs);
    }

    /**
     * <p>Checks if a CharSequence is empty (""), null or whitespace only.</p>
     *
     * <p>Whitespace is defined by {@link Character#isWhitespace(char)}.</p>
     *
     * <pre>
     * isBlank(null)      = true
     * isBlank("")        = true
     * isBlank(" ")       = true
     * isBlank("bob")     = false
     * isBlank("  bob  ") = false
     * </pre>
     *
     * @param cs  the CharSequence to check, may be null
     * @return {@code true} if the CharSequence is null, empty or whitespace only
     */
    public static boolean isBlank(final CharSequence cs) {
        final int strLen = length(cs);
        if (strLen == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if (!Character.isWhitespace(cs.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * Null-safe check if the specified map is empty.
     * <p>
     * Null returns true.
     *
     * @param map  the map to check, may be null
     * @return true if empty or null
     */
    public static boolean isEmpty(final Map<?,?> map) {
        return map == null || map.isEmpty();
    }

    /**
     * Null-safe check if the specified map is not empty.
     * <p>
     * Null returns false.
     *
     * @param map  the map to check, may be null
     * @return true if non-null and non-empty
     */
    public static boolean isNotEmpty(final Map<?,?> map) {
        return !isEmpty(map);
    }

    /**
     * Null-safe check if the specified collection is empty.
     * <p>
     * Null returns true.
     * </p>
     *
     * @param coll  the collection to check, may be null
     * @return true if empty or null
     */
    public static boolean isEmpty(final Collection<?> coll) {
        return coll == null || coll.isEmpty();
    }

    /**
     * Null-safe check if the specified collection is not empty.
     * <p>
     * Null returns false.
     * </p>
     *
     * @param coll  the collection to check, may be null
     * @return true if non-null and non-empty
     */
    public static boolean isNotEmpty(final Collection<?> coll) {
        return !isEmpty(coll);
    }


    //~内部方法


    /**
     * Gets a CharSequence length or {@code 0} if the CharSequence is
     * {@code null}.
     *
     * @param cs
     *            a CharSequence or {@code null}
     * @return CharSequence length or {@code 0} if the CharSequence is
     *         {@code null}.
     */
    private static int length(final CharSequence cs) {
        return cs == null ? 0 : cs.length();
    }

}
